const std = @import("std");
const db = @import("./db.zig");
const myzql = @import("myzql");
const String = @import("ztring").String;
const ResultSet = myzql.result.ResultSet;
const ResultRow = myzql.result.ResultRow;
const TextResultRow = myzql.result.TextResultRow;
const ResultRowIter = myzql.result.ResultRowIter;
const TextElemIter = myzql.result.TextElemIter;
const BinaryResultRow = myzql.result.BinaryResultRow;
const httpz = @import("httpz");
const student_model = @import("../models/student_model.zig");

pub fn add(student: *const student_model.Student) !bool {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();
    const client = db.get_db_client();
    const prep_res = try client.prepare(
        allocator,
        "INSERT INTO student(name, number) VALUES (?, ?)",
    );
    defer prep_res.deinit(allocator);
    const prep_stmt = try prep_res.expect(.stmt);
    const param = .{ student.name.?, student.number.? };
    _ = try client.execute(&prep_stmt, param);
    return true;
}

pub fn query(student: *const student_model.Student, response: *httpz.Response) !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();

    var sql = String.init(allocator);
    defer sql.deinit();
    try sql.concat("SELECT * FROM student ");
    try concat_cols_push(&sql, "WHERE ", student, "AND ");

    const client = db.get_db_client();
    const prep_res = try client.prepare(allocator, sql.str());
    defer prep_res.deinit(allocator);
    const prep_stmt = try prep_res.expect(.stmt);
    const query_res = try client.executeRows(&prep_stmt, .{});
    const rows: ResultSet(BinaryResultRow) = try query_res.expect(.rows);

    const res_students = try rows.iter().tableStructs(student_model.Student, allocator);
    defer res_students.deinit(allocator);

    try response.json(.{ .result = res_students.struct_list.items }, .{});
}

pub fn query_by_pk(id: i32) !student_model.Student {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();
    const client = db.get_db_client();
    const prep_res = try client.prepare(allocator, "SELECT * from student WHERE id = ?");
    defer prep_res.deinit(allocator);
    const prep_stmt = try prep_res.expect(.stmt);
    const query_res = try client.executeRows(&prep_stmt, .{id});
    const rows: ResultSet(BinaryResultRow) = try query_res.expect(.rows);
    const rows_iter = rows.iter();

    while (try rows_iter.next()) |row| {
        var student: student_model.Student = undefined;
        try row.scan(&student);
        return student;
    }

    return student_model.Student{ .id = null, .name = null, .number = null };
}

pub fn update(student: *const student_model.Student) !bool {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();

    var sql = String.init(allocator);
    defer sql.deinit();
    try sql.concat("UPDATE student SET ");
    try concat_cols_push(&sql, "", student, ",");
    try sql.concat(" WHERE id = ?");

    const client = db.get_db_client();
    const prep_res = try client.prepare(allocator, sql.str());
    defer prep_res.deinit(allocator);
    const prep_stmt = try prep_res.expect(.stmt);
    _ = try client.execute(&prep_stmt, .{student.id.?});

    return true;
}

pub fn delete(id: i32) !bool {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();
    const client = db.get_db_client();
    const prep_res = try client.prepare(allocator, "DELETE FROM student WHERE id = ?");
    defer prep_res.deinit(allocator);
    const prep_stmt = try prep_res.expect(.stmt);
    _ = try client.execute(&prep_stmt, .{id});
    return true;
}

fn concat_cols_push(buffer: *String, prefix: []const u8, param: *const student_model.Student, conj: []const u8) !void {
    // if (param.id != null) {
    //     try b.appendSlice(conj);
    //     try b.appendSlice("id = ?");
    //     var buffer: [64]u8 = undefined;
    //     const slice = buffer[0..];
    //     _ = std.fmt.formatIntBuf(slice, param.id.?, 10, .lower, .{});
    //     try b.appendSlice(slice);
    // }
    var first = true;
    if (param.name != null) {
        if (!first) {
            try buffer.concat(conj);
        } else {
            try buffer.concat(prefix);
        }
        first = false;
        try buffer.concat("name = '");
        try buffer.concat(param.name.?);
        try buffer.concat("'");
    }
    if (param.number != null) {
        if (!first) {
            try buffer.concat(conj);
        } else {
            try buffer.concat(prefix);
        }
        first = false;
        try buffer.concat("number = '");
        try buffer.concat(param.number.?);
        try buffer.concat("'");
    }
}
